package com.example.demo.service.Impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.demo.bean.PageConfig;
import com.example.demo.service.PageConfigService;
import com.example.demo.service.XfyunTtsService;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URI;
import java.net.URLEncoder;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;

@Service
public class XfyunServiceImpl implements XfyunTtsService {

    @Value("${xfyun.tts.appid}")
    private String appid;

    @Value("${xfyun.tts.api-key}")
    private String apiKey;

    @Value("${xfyun.tts.api-secret}")
    private String apiSecret;

    @Value("${xfyun.tts.url}")
    private String apiUrl;

    @Value("${xfyun.tts.voice}")
    private String voice;

    @Value("${xfyun.tts.speed}")
    private String speed;

    @Value("${xfyun.tts.volume}")
    private String volume;

    @Value("${xfyun.tts.pitch}")
    private String pitch;

    @Autowired
    private PageConfigService pageConfigService;

    @Override
    public byte[] textToSpeech(Long id) throws Exception {
        PageConfig pageConfig = pageConfigService.getById(id);
        String text = pageConfig.getSpeakerContent();

        String voice = pageConfig.getVoiceCode();
        if (voice != null && voice.length() > 1) {
            voice = pageConfig.getVoiceCode();
        } else {
            voice = "xiaoyan";
        }

        String url = createAuthUrl();
        CountDownLatch latch = new CountDownLatch(1);
        ByteBuffer[] audioData = new ByteBuffer[1];
        Exception[] exception = new Exception[1];
        AtomicBoolean connectionEstablished = new AtomicBoolean(false);

        String finalVoice = voice;
        WebSocketClient client = new WebSocketClient(new URI(url)) {
            @Override
            public void onOpen(ServerHandshake handshakedata) {
                try {
                    connectionEstablished.set(true);

                    // 构建请求数据 - 使用 fastjson
                    JSONObject frame = new JSONObject();

                    // 公共参数
                    JSONObject common = new JSONObject();
                    common.put("app_id", appid);
                    frame.put("common", common);

                    // 业务参数
                    JSONObject business = new JSONObject();
                    business.put("aue", "lame");
                    business.put("sfl", 1);
                    business.put("auf", "audio/L16;rate=16000");
                    business.put("vcn", finalVoice);
                    business.put("speed", Integer.parseInt(speed));
                    business.put("volume", Integer.parseInt(volume));
                    business.put("pitch", Integer.parseInt(pitch));
                    business.put("bgs", 0);
                    business.put("tte", "UTF8");
                    frame.put("business", business);

                    // 请求数据
                    JSONObject data = new JSONObject();
                    String textBase64 = Base64.getEncoder().encodeToString(text.getBytes(StandardCharsets.UTF_8));
                    data.put("text", textBase64);
                    data.put("status", 2);
                    frame.put("data", data);

                    this.send(frame.toJSONString());

                } catch (Exception e) {
                    System.err.println("发送请求时出错: " + e.getMessage());
                    exception[0] = e;
                    latch.countDown();
                }
            }

            @Override
            public void onMessage(String message) {
                try {
                    System.out.println("收到响应: " + message);
                    // 使用 fastjson 解析响应
                    JSONObject response = JSON.parseObject(message);
                    int code = response.getIntValue("code");

                    if (code != 0) {
                        String errorMsg = response.getString("message");
                        if (errorMsg == null) {
                            errorMsg = "未知错误";
                        }
                        exception[0] = new RuntimeException("语音合成失败: " + errorMsg);
                        latch.countDown();
                        return;
                    }

                    JSONObject data = response.getJSONObject("data");
                    if (data != null) {
                        String audio = data.getString("audio");
                        byte[] audioBytes = Base64.getDecoder().decode(audio);

                        synchronized (audioData) {
                            if (audioData[0] == null) {
                                // 第一次接收到数据
                                audioData[0] = ByteBuffer.wrap(audioBytes);
                            } else {
                                // 合并数据
                                ByteBuffer current = audioData[0];

                                // 保存当前数据
                                byte[] currentBytes = new byte[current.remaining()];
                                current.get(currentBytes);

                                // 创建新的足够大的缓冲区
                                byte[] combinedBytes = new byte[currentBytes.length + audioBytes.length];
                                System.arraycopy(currentBytes, 0, combinedBytes, 0, currentBytes.length);
                                System.arraycopy(audioBytes, 0, combinedBytes, currentBytes.length, audioBytes.length);

                                audioData[0] = ByteBuffer.wrap(combinedBytes);
                            }
                        }

                        // 检查是否完成
                        int status = data.getIntValue("status");
                        if (status == 2) {
                            latch.countDown();
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    exception[0] = e;
                    latch.countDown();
                }
            }

            @Override
            public void onClose(int code, String reason, boolean remote) {
                System.out.println("连接关闭，代码: " + code + ", 原因: " + reason + ", 远程关闭: " + remote);
                // 只有在连接成功建立后才计数，避免重复计数
                if (connectionEstablished.get()) {
                    latch.countDown();
                }
            }

            @Override
            public void onError(Exception ex) {
                System.err.println("WebSocket错误: " + ex.getMessage());
                ex.printStackTrace();
                exception[0] = ex;
                latch.countDown();
            }
        };

        try {
            System.out.println("开始连接WebSocket...");
            client.connect();

            // 等待连接建立（最多5秒）
            int retry = 0;
            while (retry < 50 && !client.isOpen()) {
                Thread.sleep(100);
                retry++;
            }

            if (!client.isOpen()) {
                throw new RuntimeException("WebSocket连接超时，无法建立连接");
            }

            System.out.println("等待语音合成完成...");
            boolean completed = latch.await(30, TimeUnit.SECONDS);

            if (!completed) {
                throw new RuntimeException("语音合成超时，30秒内未完成");
            }

            if (exception[0] != null) {
                throw exception[0];
            }

            synchronized (audioData) {
                if (audioData[0] == null || audioData[0].remaining() == 0) {
                    throw new RuntimeException("未接收到音频数据");
                }

                // 转换ByteBuffer为byte[]
                ByteBuffer buffer = audioData[0];
                byte[] result = new byte[buffer.remaining()];
                buffer.get(result);
                System.out.println("音频数据大小: " + result.length + " bytes");
                return result;
            }

        } finally {
            if (client != null) {
                try {
                    client.close();
                } catch (Exception e) {
                    System.err.println("关闭WebSocket连接时出错: " + e.getMessage());
                }
            }
        }
    }

    private String createAuthUrl() throws Exception {
        try {
            URI uri = new URI(apiUrl);
            String host = uri.getHost();
            String path = uri.getPath();

            // 生成RFC1123格式的日期
            SimpleDateFormat sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
            sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
            String date = sdf.format(new Date());

            // 构建签名字符串
            String signatureOrigin = "host: " + host + "\n" +
                    "date: " + date + "\n" +
                    "GET " + path + " HTTP/1.1";

            System.out.println("签名原始字符串: " + signatureOrigin);

            // 使用HmacSHA256生成签名
            Mac mac = Mac.getInstance("HmacSHA256");
            SecretKeySpec spec = new SecretKeySpec(apiSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            mac.init(spec);
            byte[] signatureBytes = mac.doFinal(signatureOrigin.getBytes(StandardCharsets.UTF_8));
            String signature = Base64.getEncoder().encodeToString(signatureBytes);

            // 构建authorization
            String authorizationOrigin = String.format("api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"",
                    apiKey, "hmac-sha256", "host date request-line", signature);

            String authorization = Base64.getEncoder().encodeToString(authorizationOrigin.getBytes(StandardCharsets.UTF_8));

            // 构建最终URL
            String resultUrl = String.format("%s?authorization=%s&date=%s&host=%s",
                    apiUrl,
                    URLEncoder.encode(authorization, "UTF-8"),
                    URLEncoder.encode(date, "UTF-8"),
                    URLEncoder.encode(host, "UTF-8"));

            System.out.println("生成的认证URL: " + resultUrl);
            return resultUrl;

        } catch (Exception e) {
            System.err.println("创建认证URL失败: " + e.getMessage());
            throw new RuntimeException("认证URL生成失败", e);
        }
    }
}